Skip to content

fix(tagLabel): lenient appliedAt date deserialization#27771

Open
Khairajani wants to merge 5 commits intomainfrom
fix_taglabel_appliedat_lenient_parse
Open

fix(tagLabel): lenient appliedAt date deserialization#27771
Khairajani wants to merge 5 commits intomainfrom
fix_taglabel_appliedat_lenient_parse

Conversation

@Khairajani
Copy link
Copy Markdown
Contributor

Summary

TagLabel.appliedAt is typed java.util.Date and the global Jackson ObjectMapper is configured with SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'") — which strictly requires 6-digit fractional seconds on parse. Python clients using Pydantic emit datetimes via datetime.isoformat(), which omits the fractional part entirely when microsecond == 0 (~1/1000 odds per timestamp). The result is a payload like "2026-04-24T10:27:06Z" that the server cannot deserialize, surfacing as:

RuntimeException: Failed to convert JsonValue to target class
  caused by: Cannot deserialize value of type `java.util.Date` from String "2026-04-24T10:27:06Z":
             Unparseable date  (through reference chain: Table["columns"]→Column["tags"]→TagLabel["appliedAt"])

This was causing intermittent automator propagation failures in CI — every PATCH carrying a round-tripped appliedAt with microsecond=0 was being rejected. Same class of bug as the tag_usage.appliedAt precision fix in the 1.11.8 / 1.12.0 MySQL migrations, just on the wire side.

Fix

Register a Jackson mixin on TagLabel that deserializes appliedAt via Instant.parse(), which accepts both forms:

  • "2026-04-24T10:27:06Z" (no fractional)
  • "2026-04-24T10:27:06.918000Z" (with fractional)

Mixin is added to the global OBJECT_MAPPER before any .copy(), so all five derived mappers inherit it. No generated code is touched. Serialization is unchanged (still always emits 6-digit fractional from the global format).

Test plan

  • Added JsonUtilsTest#testTagLabelAppliedAtAcceptsBareSecondPrecision covering both forms
  • mvn compile -pl openmetadata-spec passes
  • mvn spotless:apply clean
  • CI integration tests

@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@Khairajani Khairajani added the safe to test Add this label to run secure Github workflows on PRs label Apr 27, 2026
Accept ISO-8601 datetimes with or without fractional seconds for
TagLabel.appliedAt. Python clients omit fractional when a datetime's
microsecond is zero, emitting strings like "2026-04-24T10:27:06Z" that
the strict global SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'")
rejects, causing PATCH operations to fail with "Failed to convert
JsonValue to target class".
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 27, 2026

🔴 Playwright Results — 19 failure(s), 15 flaky

✅ 3941 passed · ❌ 19 failed · 🟡 15 flaky · ⏭️ 86 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 297 0 2 4
🟡 Shard 2 743 0 2 8
🟡 Shard 3 746 0 2 7
🔴 Shard 4 755 1 3 18
🔴 Shard 5 673 12 2 41
🔴 Shard 6 727 6 4 8

Genuine Failures (failed on all attempts)

Pages/Entity.spec.ts › Tag Add, Update and Remove for child entities (shard 4)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/EntityDataConsumer.spec.ts › Tag Add, Update and Remove for child entities (shard 5)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/EntityDataSteward.spec.ts › Tag Add, Update and Remove for child entities (shard 5)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for locator('[data-row-key="snowflake_task"]').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for table (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for dashboard (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for pipeline (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for topic (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for database (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for databaseSchema (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for dashboardDataModel (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for mlmodel (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for container (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ExplorePageRightPanel.spec.ts › Should perform CRUD and Removal operations for searchIndex (shard 5)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m200�[39m
Received: �[31m500�[39m
Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    19 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).not.�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator:  getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')
Expected: not visible
Received: visible
Timeout:  15000ms

Call log:
�[2m  - Expect "not toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('KnowledgePanel.Tags').getByTestId('tags-container').getByTestId('tag-PII.None')�[22m
�[2m    18 × locator resolved to <span data-testid="tag-PII.None" class="ant-typography ant-typography-ellipsis ant-typography-single-line ant-typography-ellipsis-single-line m-0 tags-label text-truncate truncate w-max-full">None</span>�[22m
�[2m       - unexpected value "visible"�[22m

🟡 15 flaky test(s) (passed on retry)
  • Pages/SearchSettings.spec.ts › Update global search settings (shard 1, 1 retry)
  • Pages/UserCreationWithPersona.spec.ts › Create user with persona and verify on profile (shard 1, 1 retry)
  • Features/ActivityAPI.spec.ts › Activity event is created when description is updated (shard 2, 1 retry)
  • Features/ActivityAPI.spec.ts › Activity event is created when owner is added (shard 2, 1 retry)
  • Features/RTL.spec.ts › Verify Following widget functionality (shard 3, 1 retry)
  • Flow/MetricSearch.spec.ts › searching for a metric with a long multi-word name should not cause clause explosion (shard 3, 1 retry)
  • Pages/DataContracts.spec.ts › Create Data Contract and validate for Table (shard 4, 1 retry)
  • Pages/DataContracts.spec.ts › Create Data Contract and validate for MlModel (shard 4, 1 retry)
  • Pages/DataContracts.spec.ts › Create Data Contract and validate for ApiEndpoint (shard 4, 1 retry)
  • Pages/Entity.spec.ts › Tier Add, Update and Remove (shard 5, 1 retry)
  • Pages/EntityDataConsumer.spec.ts › No edit owner permission (shard 5, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify lineage schema filter selection (shard 6, 1 retry)
  • Pages/Lineage/LineageRightPanel.spec.ts › Verify custom properties tab IS visible for supported type: searchIndex (shard 6, 1 retry)
  • Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6, 2 retries)
  • Pages/ServiceEntity.spec.ts › Tag Add, Update and Remove (shard 6, 2 retries)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

Khairajani and others added 2 commits April 28, 2026 12:37
…ption

JsonUtils.readValue catches JsonProcessingException and rethrows as
JsonParsingException, so the public-API caller observes the wrapper.
Assert on the wrapper type and verify the cause chain carries the
underlying Jackson mapping exception with the field path context.
@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented Apr 28, 2026

Code Review ✅ Approved 1 resolved / 1 findings

Updates tagLabel deserialization to use LenientIsoDateDeserializer, resolving the unhandled DateTimeParseException. The implementation is robust and no further issues were found.

✅ 1 resolved
Edge Case: LenientIsoDateDeserializer doesn't wrap DateTimeParseException

📄 openmetadata-spec/src/main/java/org/openmetadata/schema/utils/JsonUtils.java:912-918
Instant.parse(value) throws an unchecked DateTimeParseException for malformed input. While Jackson's infrastructure will catch it and surface an error, wrapping it in a ctxt.handleUnexpectedToken(...) or JsonMappingException would produce a cleaner, more consistent error message with the JSON path context (e.g., through reference chain: ...TagLabel["appliedAt"]) rather than an unwrapped runtime exception.

In practice this is low-impact because Jackson does catch RuntimeException during deserialization and re-wraps it, but explicit handling is the idiomatic Jackson pattern and gives better diagnostics.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant